/*
 * Copyright 2016-2019 yoara
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package yhao.infra.service.datasource.mybatis.interceptor;

import org.apache.ibatis.executor.statement.StatementHandler;
import org.apache.ibatis.plugin.Intercepts;
import org.apache.ibatis.plugin.Invocation;
import org.apache.ibatis.plugin.Plugin;
import org.apache.ibatis.plugin.Signature;
import org.apache.ibatis.session.ResultHandler;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import yhao.infra.common.InfraCommonConstants;

import java.sql.Statement;
import java.util.LinkedList;
import java.util.Properties;

/**
 * sql执行统计拦截器
 *
 * @author yoara
 */
@Intercepts({@Signature(method = "batch", type = StatementHandler.class, args = {Statement.class}),
        @Signature(method = "update", type = StatementHandler.class, args = {Statement.class}),
        @Signature(method = "query", type = StatementHandler.class, args = {Statement.class, ResultHandler.class})
})
public class SqlStatInterceptor extends AbstractInterceptor {
    private static ThreadLocal<LinkedList<StatInfo>> sqlLocal = new ThreadLocal<>();

    private final static Logger logger = LoggerFactory.getLogger(InfraCommonConstants.SQLLOGGER);

    public static void initStat(String sql){
        LinkedList<StatInfo> list = sqlLocal.get();
        if(list==null){
            list = new LinkedList();
            sqlLocal.set(list);
        }
        list.push(new StatInfo(sql));
    }

    public static void clearStat(){
        sqlLocal.remove();
    }

    @Override
    public Object intercept(Invocation invocation) throws Throwable {
        Object result;
        try {
            result = invocation.proceed();
        } finally {
            LinkedList<StatInfo> list = sqlLocal.get();
            if(list!=null){
                if(list.size()>0){
                    StatInfo stat = list.pop();
                    logger.info("[sql]" + stat.getSql() + ",[time(ms)]"+
                            (System.currentTimeMillis()-stat.getStartLong()));
                }
                if(list.size()==0){
                    clearStat();
                }
            }
        }
        return result;
    }

    @Override
    public Object plugin(Object target) {
        return Plugin.wrap(target, this);
    }

    @Override
    public void setProperties(Properties properties) {}

    public static class StatInfo{
        private String sql;
        private long startLong;

        public StatInfo(String sql) {
            this.sql = sql;
            this.startLong = System.currentTimeMillis();
        }

        public String getSql() {
            return sql;
        }

        public long getStartLong() {
            return startLong;
        }
    }
}
